<template>
  <div class="chat-layout">
    <!-- 左：模型选择 -->
    <div class="left">
      <ModelSelector />
    </div>

    <!-- 中：会话历史 -->
    <div class="middle">
      <ChatHistory />
    </div>

    <!-- 右：聊天 -->
    <div class="right">
      <div class="chat" ref="chatRef">
        <!-- ✅ 新增：内容容器 -->
        <div class="chat-content" ref="contentRef">
          <div
            v-for="(m, i) in store.messages"
            :key="i"
            :class="['msg', m.role === 'user' ? 'user' : 'assistant']"
          >
            <div class="avatar" aria-hidden="true">
              <span v-if="m.role === 'user'">你</span>
              <span v-else>AI</span>
            </div>
            <div class="bubble">
              <MarkdownRenderer :content="m.content" />
            </div>
          </div>

          <!-- ✅ 新增：滚动锚点 -->
          <div ref="endRef" class="scroll-anchor"></div>
        </div>
      </div>

      <div class="input-bar">
        <textarea
          v-model="input"
          :placeholder="placeholder"
          :disabled="store.streaming"
          @keydown.enter.exact.prevent="send"
        />
        <button class="btn primary" :disabled="!input.trim() || store.streaming" @click="send">发送</button>
        <button class="btn ghost" :disabled="!store.streaming" @click="abort">中断</button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
import {useChatStore} from '@/stores/chat';
import { API_BASE_URL, MODELS } from '@/config/api';
import MarkdownRenderer from '@/components/MarkdownRenderer.vue';
import ModelSelector from '@/components/ModelSelector.vue';
import ChatHistory from '@/components/ChatHistory.vue';

const store = useChatStore();
const chatRef = ref<HTMLElement | null>(null);
const contentRef = ref<HTMLElement | null>(null); // ✅ 新增：内容容器
const endRef  = ref<HTMLElement | null>(null);   // ✅ 锚点

const input = ref('');
const placeholder = '请输入内容，Enter 发送。';

let controller: AbortController | null = null;


onMounted(async () => {
  // 刷新后拉取会话列表（不自动选中）
  await store.fetchSessions();
});
async function ensureSessionIfNeeded(seedTitle?: string){
  if (store.currentSessionId) return;
  const id = await store.createSession();        // ✅ 不传参
  if (seedTitle) {
    await store.renameSession(id, seedTitle.slice(0, 40)); // ✅ 用首条消息做标题
  }
}

async function send(){
  const content = input.value.trim();
  if(!content || store.streaming) return;

  // 没有选中的会话则自动创建
  await ensureSessionIfNeeded(content);
  // 再次确认：如果仍没有会话，直接返回
  if(!store.currentSessionId) return;

  // 置顶当前会话（可选，但体验更好）
  store.touchSession(store.currentSessionId);

  store.appendMessage({ role:'user', content });
  store.appendMessage({ role:'assistant', content: '' });

  input.value = '';
  store.setStreaming(true);
  controller = new AbortController();

  const modelParam = MODELS[store.model].apiParam;

  try{
    const r = await fetch(`${API_BASE_URL}/api/chat/stream?session_id=${store.currentSessionId}&model=${modelParam}`, {
      method: 'POST',
      headers: { 'Content-Type':'application/json' },
      body: JSON.stringify({ messages: store.messages }),
      signal: controller.signal,
    });
    if(!r.ok || !r.body) throw new Error(`HTTP ${r.status}`);
    // 会话有新消息，更新“最近使用时间”并把它顶到列表前面
    store.touchSession(store.currentSessionId);
    const reader = r.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let buffer = '';

    while(true){
      const { value, done } = await reader.read();
      if(done) break;
      buffer += decoder.decode(value, { stream: true });

      const parts = buffer.split('\n\n');
      for(let i=0; i<parts.length-1; i++){
        const chunk = parts[i];
        if(chunk.startsWith('data: ')){
          const payload = chunk.slice(6).trim();
          if(payload !== '[DONE]') store.updateLastAssistantDelta(payload);
        }else{
          store.updateLastAssistantDelta(chunk);
        }
      }
      buffer = parts[parts.length-1];
    }
  }catch(err){
    store.updateLastAssistantDelta(`\n\n> 请求中断或失败：${String(err)}`);
  }finally{
    store.setStreaming(false);
    controller = null;
  }
}
function abort(){ if(controller) controller.abort(); }
onBeforeUnmount(() => { if(controller) controller.abort(); });


// 是否“贴底”状态（用户没主动往上滚）
const shouldStick = ref(true);
const SCROLL_TOL = 32; // 距离底部多少像素内视为“贴底”
function isAtBottom(el: HTMLElement){
  return el.scrollHeight - (el.scrollTop + el.clientHeight) <= SCROLL_TOL;
}
function onChatScroll(){
  if (!chatRef.value) return;
  shouldStick.value = isAtBottom(chatRef.value);
}
function autoScroll(force = false){
  const el = chatRef.value;
  if (!el) return;
  if (force || shouldStick.value) {
    // 想要动画可用 behavior: 'smooth'（流式时可能有轻微动画累积）
    el.scrollTo({ top: el.scrollHeight });
  }
}
// 用锚点滚到底；流式时用 behavior:'auto'，避免平滑动画落后
function scrollToEnd(force = false){
  const el = chatRef.value;
  const anchor = endRef.value;
  if (!el || !anchor) return;

  if (force || shouldStick.value) {
    // 双 rAF，等一轮/两轮布局（Markdown/公式/代码块）
    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        anchor.scrollIntoView({ block: 'end', behavior: 'auto' });
      });
    });
  }
}
// 1) 新增消息（插入 user + 占位 assistant）时，强制到底
watch(() => store.messages.length, async () => {
  await nextTick();
  scrollToEnd(true);
});
// 监听“最后一条消息内容变化”（流式增量），仅在贴底时滚动
watch(
  () => store.messages.length ? store.messages[store.messages.length - 1].content : '',
  async () => {
    await nextTick();
    autoScroll(false);
  }
);
// 2) 流式增量：仅在贴底时跟随
watch(
  () => store.messages.length ? store.messages[store.messages.length - 1].content : '',
  async () => {
    await nextTick();
    scrollToEnd(false);
  }
);
onMounted(() => {
  chatRef.value?.addEventListener('scroll', onChatScroll, { passive: true });
});
onBeforeUnmount(() => {
  chatRef.value?.removeEventListener('scroll', onChatScroll);
});
// 4) ✅ 观察“内容容器”尺寸变化（Markdown 渲染/代码高亮/数学公式/行号等都会触发）
let roContent: ResizeObserver | null = null;
onMounted(() => {
  if (contentRef.value) {
    roContent = new ResizeObserver(() => scrollToEnd(false));
    roContent.observe(contentRef.value);
  }
});
onBeforeUnmount(() => {
  roContent?.disconnect();
  roContent = null;
});
// 5) ✅ 监听图片加载（子元素 load 冒泡不到父，但在捕获阶段能监听到）
function onImgLoad(){ scrollToEnd(false); }
onMounted(() => {
  chatRef.value?.addEventListener('load', onImgLoad, true); // useCapture = true
});
onBeforeUnmount(() => {
  chatRef.value?.removeEventListener('load', onImgLoad, true);
});
</script>

<style scoped>
.chat-layout{
  display: grid;
  width: 100%;
  height: 100%;
  min-height: 0;
  grid-template-columns: 260px 300px minmax(0, 1fr);  /* 添加 minmax 限制 */
  gap: 16px;
  overflow: hidden;  /* 防止溢出 */
}

/* 三列自身不滚动，由内部具体块滚动 */
.left, .middle, .right{
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* 左列：模型选择卡片内部滚动，底部贴近 Tag */
.left .card{
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

/* 中列：历史列表内部滚动 */
.middle .history{
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

/* 右列：消息区滚动 + 底部输入固定 */
.right{
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 10px;
  min-height: 0;
}
.right .chat{
  min-height: 0;
  width: 100%;          /* 防止出现“窄盒子” */
  overflow: auto;
}
/* 输入区 */
.input-bar{
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 8px;
  align-items: end;
  padding: 8px 12px 12px;
  border-top: 1px solid var(--ui-border, #e5e7eb);
  background: var(--ui-surface, #fff);
}
.input-bar textarea{
  height: 92px;
  resize: none;
  padding: 10px 12px;
  border: 1px solid var(--ui-border, #e5e7eb);
  border-radius: 10px;
  outline: none;
}
.btn{
  height: 40px;
  padding: 0 14px;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: pointer;
}
.btn.primary{
  background: #3b82f6;
  color: #fff;
}
.btn.ghost{
  background: #fff;
  border-color: #e5e7eb;
  color: #374151;
}

/* 聊天气泡 */
.msg{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 8px;
  margin-bottom: 14px;
  align-items: flex-start;
}
.msg.user{
  grid-template-columns: 1fr auto;
  justify-items: end;
}
.avatar{
  width: 28px; height: 28px;
  border-radius: 50%;
  background: #e5e7eb;
  display: grid;
  place-items: center;
  font-size: 12px;
  color: #111827;
}
.msg.user .avatar{ background: #dbeafe; color: #1e40af; }

.bubble{
  max-width: min(720px, 92%);
  padding: 10px 14px;
  border-radius: 14px;
  border: 1px solid var(--bubble-border, #e5e7eb);
  background: var(--bubble-bg, #fff);
  box-shadow: 0 1px 0 rgba(0,0,0,0.02);
}
.msg.assistant .bubble{
  --bubble-bg: #f7f9fd;             /* 模型气泡底色（浅） */
  --bubble-border: #e6ebf5;
  border-top-left-radius: 6px;       /* 让两侧造型略有差异 */
}
.msg.user .bubble{
  --bubble-bg: #eef6ff;              /* 用户气泡底色 */
  --bubble-border: #d7e7ff;
  border-top-right-radius: 6px;
}
.scroll-anchor { height: 1px; }

/* 让左右两列内部滚动而非整个页面滚动 */
.left .card,
.middle .history{
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

/* 适配 */
@media (max-width: 1200px){
  .chat-layout{
    grid-template-columns: minmax(180px, 220px) minmax(200px, 240px) minmax(0, 1fr);
  }
}
@media (max-width: 900px){
  .chat-layout{ grid-template-columns: 1fr; }
}
</style>

